package main

import (
	"fgo/tools/img/db"
	"fgo/tools/img/utils"
	"flag"
	"fmt"
	log "github.com/sirupsen/logrus"
	"gopkg.in/mgo.v2/bson"
	"io"
	"math"
	"net/http"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"sync"
	"time"
)

type task struct {
	ComicID   string
	ChapterID string
	PicOrder  int
	Source    string
	Image     string
	IsCover   bool
}

var source string
var downloadPath string

// tuhao
// hanmanku
// bbdmw
// hanmanwo
var ch = make(chan int, 10)
var allType []string = []string{
	"tuhao", "hanmanku", "bbdmw", "hanmanwo", "manhuatai",
}

func init() {
	const (
		defaultSource = "hanmanwo"
		usage         = "数据源: e.g: tuhao,hanmanku,bbdmw,hanmanwo,manhuatai,all(排除 manhuatai)"

		defaultDownloadPath = "./comic_download"
	)
	flag.StringVar(&source, "s", defaultSource, usage)
	flag.StringVar(&downloadPath, "d", defaultDownloadPath, "下载位置")
}

func main() {
	flag.Parse()

	if source == "all" {
		all()
		return
	}
	if source == "manhuatai" {
		manhuatai()
		return
	}
	hanman()
}

// 全部漫画
func all() {
	for _, item := range allType {
		if item == "manhuatai" {
			manhuatai()
		} else {
			hanman()
		}
	}
}

// 漫画台
func manhuatai() {
	m := db.ManhuataiComicList{}
	var (
		imgDomain = "http://mhpic.cnmanhua.com"
		pageSize  = 5
		total     = db.DataTotal(m, bson.M{})
		wg        = &sync.WaitGroup{}
	)
	pageNum := math.Ceil(float64(total) / float64(pageSize))
	for i := 1; i <= int(pageNum); i++ {
		//分页查询
		log.Infof("===> 正在拉取 ManhuataiComicList ,  Source: %s,Page: %d", source, i)
		var booksRes []db.ManhuataiComicList
		err := db.SearchData(&booksRes, db.ManhuataiComicList{}, bson.M{}, "_id", bson.M{}, (i-1)*pageSize, pageSize)
		if err != nil {
			log.Errorf("err:%v", err)
		}
		for _, item := range booksRes {
			comicID := strconv.Itoa(item.ComicId)
			// 封面下载
			wg.Add(1)
			ch <- 1
			go handle(wg, task{
				ComicID:   comicID,
				ChapterID: "-1",
				Source:    source,
				Image:     fmt.Sprintf("https://image.yqmh.com/mh/%s.jpg-300x400.webp", comicID),
				PicOrder:  -1,
				IsCover:   true,
			})

			// 查询全部章节
			var chapterRes db.ManhuataiItem
			err := db.GetOneData(&chapterRes, bson.M{
				"comic_id": item.ComicId,
			})
			if err != nil {
				log.Errorf("err:%v", err)
			}
			log.Infof("===> 正在拉取 ManhuataiItem , Source: %s, ComicID:%s, total: %d", source, comicID, len(chapterRes.ComicChapter))
			for _, chapter := range chapterRes.ComicChapter {
				for i := chapter.StartNum; i <= chapter.EndNum; i++ {
					url := fmt.Sprintf("%s%s-mht.middle.webp", imgDomain, strings.Replace(chapter.Rule, "$$", strconv.Itoa(i), -1))
					wg.Add(1)
					ch <- 1
					go handle(wg, task{
						ComicID:   comicID,
						ChapterID: chapter.ChapterId,
						PicOrder:  i,
						Source:    "manhuatai",
						Image:     url,
						IsCover:   false,
					})
				}
			}
		}
	}
	wg.Wait()
}

// 韩漫
func hanman() {
	m := db.ManhuaHanmanBooks{}
	pageSize := 5
	total := db.DataTotal(m, bson.M{
		"comic_source": source,
	})
	var wg = &sync.WaitGroup{}
	pageNum := math.Ceil(float64(total) / float64(pageSize))
	for i := 1; i <= int(pageNum); i++ {
		//分页查询
		log.Infof("===> 正在拉取 ManhuaHanmanBooks ,  Source: %s,Page: %d", source, i)
		var booksRes []db.ManhuaHanmanBooks
		err := db.SearchData(&booksRes, db.ManhuaHanmanBooks{}, bson.M{
			"comic_source": source,
		}, "_id", bson.M{}, (i-1)*pageSize, pageSize)
		if err != nil {
			log.Errorf("err:%v", err)
		}
		for _, item := range booksRes {
			// 查询全部章节
			var chapterRes []db.ManhuaHanmanChapter
			err := db.GetTotalData(&chapterRes, db.ManhuaHanmanChapter{}, bson.M{
				"chapter_source": source,
				"comic_id":       item.ComicID,
			})
			// 封面下载
			wg.Add(1)
			ch <- 1
			go handle(wg, task{
				ComicID:   item.ComicID,
				ChapterID: "-1",
				Source:    source,
				Image:     item.ComicCoverImg,
				PicOrder:  -1,
				IsCover:   true,
			})

			// 章节图片下载
			log.Infof("===> 正在拉取 ManhuaHanmanChapter , Source: %s, ComicID:%s, total: %d", source, item.ComicID, len(chapterRes))
			if err != nil {
				log.Errorf("err:%v", err)
			}
			for _, chapter := range chapterRes {
				for _, image := range chapter.Photos {
					wg.Add(1)
					ch <- 1
					go handle(wg, task{
						ComicID:   chapter.ComicID,
						ChapterID: chapter.ChapterID,
						Source:    source,
						Image:     image.Url,
						PicOrder:  image.PicOrder,
					})
				}
			}
		}
	}
	wg.Wait()
}

func handle(wg *sync.WaitGroup, task task) {
	defer wg.Done()
	NetDownloadImage(task)
	<-ch
}

// 图片下载
func NetDownloadImage(task task) {
	var (
		pathInfo, _ = filepath.Abs(downloadPath)
		name        = strconv.Itoa(task.PicOrder) + filepath.Ext(task.Image)
		basePath    = filepath.Join(pathInfo, task.Source, task.ComicID, task.ChapterID)
	)
	// 封面
	if task.IsCover {
		basePath = filepath.Dir(basePath)
		name = "cover" + filepath.Ext(task.Image)
	}
	localPath := filepath.Join(basePath, name)
	// 判断父级目录是否存在
	if !utils.PathExistsLocal(basePath) {
		if err := os.MkdirAll(basePath, os.ModePerm); err != nil {
			panic(err)
		}
	}
	// 判断本地文件是否存在,如果存在则跳过
	if utils.PathExistsLocal(localPath) {
		return
	}
	var (
		fsize int64
	)
	// 请求
	client := &http.Client{
		Timeout: time.Second * 60, //设置超时时间
	}
	req, err := http.NewRequest("GET", task.Image, nil)
	if err != nil {
		log.Errorf("err:%v , ==> %s", err, task.Image)
		return
	}
	req.Header.Set("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36")
	resp, err := client.Do(req)
	if err != nil {
		log.Errorf("err:%v , ==> %s", err, task.Image)
		return
	}
	//读取服务器返回的文件大小
	fsize, err = strconv.ParseInt(resp.Header.Get("Content-Length"), 10, 32)
	if err != nil {
		log.Errorf("err:%v , ==> %s", err, task.Image)
	}
	// 根据文件大小判断文件是否存在
	if utils.PathExistsWithSize(localPath, fsize) {
		return
	}
	f, err := os.OpenFile(localPath, os.O_RDWR|os.O_CREATE, 0666)
	if err != nil {
		log.Errorf("err:%v , ==> %s", err, task.Image)
	}
	_, err = io.Copy(f, resp.Body)
	if err != nil {
		log.Errorf("err:%v , ==> %s", err, task.Image)
	}
	log.Infof("===> image: %s, size: %d finished", task.Image, fsize)
}
